package com.cloudkinto.service.channel.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.service.system.SystemSetService;
import com.cloudkinto.vo.system.omp.OmpSystemEntity;
import com.cloudkinto.vo.system.wms.WmsSystemEntity;
import com.cloudkinto.vo.warehouse.ChannelWarehouseVo;
import com.cloudkinto.entity.*;
import com.cloudkinto.service.channel.LcChannelRuleService;
import com.cloudkinto.service.channel.LogisticsChannelService;
import com.cloudkinto.service.user.UserService;
import com.cloudkinto.service.warehouse.WarehouseService;
import com.cloudkinto.vo.lc.*;
import com.cloudkinto.vo.warehouse.WarehouseRes;
import com.cloudkinto.utils.BeanCopierUtils;
import com.cloudkinto.vo.channel.la.LaSwitchReq;
import com.cloudkinto.vo.channel.lc.*;
import com.cloudkinto.vo.wr.qs.QsEt;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author hua
 * @since 2024-10-29
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class LogisticsChannelServiceImpl extends ServiceImpl<LogisticsChannelDao, LogisticsChannelDo> implements LogisticsChannelService {
    @Autowired
    private LogisticsChannelDao dao;
    @Autowired
    private LcShippingStorageDao lcShippingStorageDao;
    @Autowired
    private LcShippingAddressDao lcShippingAddressDao;
    @Autowired
    private LcCompanyDao lcCompanyDao;
    @Autowired
    private LcChannelRuleService lcChannelRuleService;
    @Autowired
    private LcChannelRuleDao lcChannelRuleDao;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private UserService userService;
    @Autowired
    private QuotationSchemeDao quotationSchemeDao;
    @Autowired
    private SystemSetService systemSetService;

    @Override
    public SingleResult addInit() {
        return SingleResult.success("");
    }


    public void checkName(String code, Long id, Long tenantId) {
        if (StringUtils.isBlank(code))
            throw new BizException(SysConstant.Add_Name_Empty);
        //名称不能重复
        LogisticsChannelDo et = dao.selectOne(new LambdaQueryWrapper<LogisticsChannelDo>()
                .ne(id != null, LogisticsChannelDo::getId, id)
                .eq(LogisticsChannelDo::getChannelCode, code)
                .eq(LogisticsChannelDo::getTenantId, tenantId).last(" limit 1"));

        if (et != null) throw new BizException(SysConstant.Add_Name_Same);
    }

    @Override
    public Object addLaChannel(LcChannelAddReq req, Long userId, Long tenantId) {
        this.checkName(req.getChannelCode(), null, tenantId);
        LogisticsChannelDo entityDo = new LogisticsChannelDo();
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setTenantId(tenantId);
        handlerAddBefore(entityDo, userId);
        dao.insert(entityDo);
        //第一次添加需要加两条默认下单规则
//        LcChannelRuleDo ruleDo = new LcChannelRuleDo(StaticDict.Channel_Calculate_Type.Shortest_Size.getValue(), StaticDict.Rule_Operate_Sign.Greater_Than.getValue(), 10F, null, 0, entityDo.getId());
//        lcChannelRuleDao.insert(ruleDo);
//        LcChannelRuleDo ruleDo2 = new LcChannelRuleDo(StaticDict.Channel_Calculate_Type.Longest_Side.getValue(), StaticDict.Rule_Operate_Sign.Less_Than.getValue(), 100F, null, 0, entityDo.getId());
//        lcChannelRuleDao.insert(ruleDo2);
        return entityDo.getId();

    }

    //做新增之前要执行的业务定制处理
    private void handlerAddBefore(LogisticsChannelDo entityDo, Long userId) {
        entityDo.setCreateBy(userId);
        entityDo.setCreateTime(new Date());
        entityDo.setDeleteFlag(SysConstant.DELETE_FLAG_FALSE);
    }

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    @Override
    public Object update(LcUpdateReq req, Long userId, Long tenantId) {
        LogisticsChannelDo et = dao.selectById(req.getId());
        if (et == null) throw new BizException(SysConstant.No_Data);
        BeanUtils.copyProperties(req, et);
        et.setUpdateBy(userId);
        dao.updateById(et);
        //更新仓库
        List<LcStorageVo> storages = lcShippingStorageDao.getChannelStorage(et.getId());
        List<Long> newStorageIds = req.getStorages().stream().map(LcStorageVo::getStorageId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<Long> deleteStorageIds = storages.stream().map(LcStorageVo::getStorageId).filter(i -> !newStorageIds.contains(i)).distinct().collect(Collectors.toList());
        if (!deleteStorageIds.isEmpty()) {//判断有没有报价 关联该物流渠道， 且物流渠道绑定得仓库是不是在删除集合内
            int lcUseCount = quotationSchemeDao.getLcUseCount(deleteStorageIds, et.getId(), tenantId);
            if (lcUseCount > 0) {
                Map<Long, String> storageMap = warehouseService.getList(tenantId).stream().collect(Collectors.toMap(WarehouseRes::getId, WarehouseRes::getWhCode));
                StringBuilder storageName = new StringBuilder();
                for (Long storageId : deleteStorageIds) {
                    if (storageName.length() > 0) storageName.append(",");
                    storageName.append(storageMap.get(storageId));
                }
                throw new BizException(SysConstant.LC_Storage_Related_WithName, storageName.toString());
            }
            lcShippingStorageDao.updateDelete(deleteStorageIds, et.getId(), userId);
        }
        for (LcStorageVo storage : req.getStorages()) {
            if (storage.getId() != null) continue;
            LcShippingStorageDo shippingStorageDo = new LcShippingStorageDo();
            BeanUtils.copyProperties(storage, shippingStorageDo);
            shippingStorageDo.setChannelId(et.getId());
            shippingStorageDo.setCreateBy(userId);
            lcShippingStorageDao.insert(shippingStorageDo);
        }
        //发货地址
        List<LcShippingAddressDetailVo> address = lcShippingAddressDao.getShippingAddress(et.getId());
        List<Long> oldAddressIds = req.getAddress().stream().map(LcShippingAddressDetailVo::getId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> deleteAddressIds = address.stream().map(LcShippingAddressDetailVo::getId).filter(i -> !oldAddressIds.contains(i)).collect(Collectors.toList());
        if (!deleteAddressIds.isEmpty()) lcShippingAddressDao.updateDelete(deleteAddressIds, userId);
        for (LcShippingAddressDetailVo reqAddress : req.getAddress()) {
            if (reqAddress.getId() != null) {
                lcShippingAddressDao.updateAddress(reqAddress, userId);
            } else {
                LcShippingAddressDo lcShippingAddressDo = new LcShippingAddressDo();
                BeanUtils.copyProperties(reqAddress, lcShippingAddressDo);
                lcShippingAddressDo.setCreateBy(userId);
                lcShippingAddressDo.setChannelId(et.getId());
                lcShippingAddressDao.insert(lcShippingAddressDo);
            }
        }
        //绑定客户
        this.updateCompany(et.getId(), req.getCompany(), userId);
        //下单限制
        List<LcRuleDetailRes> channelRule = lcChannelRuleService.getChannelRule(et.getId());
        List<Long> oldRuleIds = req.getRules().stream().map(LcRuleDetailRes::getId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> deleteRuleIdIds = channelRule.stream().map(LcRuleDetailRes::getId).filter(i -> !oldRuleIds.contains(i)).collect(Collectors.toList());
        if (!deleteRuleIdIds.isEmpty()) lcChannelRuleDao.updateDelete(deleteRuleIdIds, userId);
        for (LcRuleDetailRes reqRule : req.getRules()) {
            if (reqRule.getId() != null) {
                lcChannelRuleDao.updateRule(reqRule, userId);
            } else {
                LcChannelRuleDo ruleDo = new LcChannelRuleDo();
                BeanUtils.copyProperties(reqRule, ruleDo);
                ruleDo.setCreateBy(userId);
                ruleDo.setChannelId(et.getId());
                lcChannelRuleDao.insert(ruleDo);
            }
        }
        return et.getId();
    }

    public void updateCompany(Long id, List<LcCompanyVo> company, Long userId) {
        //绑定客户
        List<LcCompanyVo> channelCompany = lcCompanyDao.getChannelCompany(id);
        List<Long> oldCompanyIds = company.stream().map(LcCompanyVo::getId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> deleteCompanyIdIds = channelCompany.stream().map(LcCompanyVo::getId).filter(i -> !oldCompanyIds.contains(i)).collect(Collectors.toList());
        if (!deleteCompanyIdIds.isEmpty()) lcCompanyDao.updateDelete(deleteCompanyIdIds, userId);
        for (LcCompanyVo reqCompany : company) {
            if (reqCompany.getId() != null) continue;
            LcCompanyDo lcCompanyDo = new LcCompanyDo();
            BeanUtils.copyProperties(reqCompany, lcCompanyDo);
            lcCompanyDo.setCreateBy(userId);
            lcCompanyDo.setChannelId(id);
            lcCompanyDao.insert(lcCompanyDo);
        }
        //下
    }


    @Override
    public void apiCodeUpdate(ApiCodeUpdateReq req, Long userId) {
        LogisticsChannelDo et = dao.selectById(req.getId());
        if (et == null) throw new BizException(SysConstant.No_Data);
        et.setCarrierCode(req.getCarrierCode());
        et.setUpdateBy(userId);
        dao.updateById(et);
    }

    @Override
    public int delete(Long id, Long userId) {
        LogisticsChannelDo entityDo = dao.selectById(id);
        return dao.deleteById(id);
    }

    public LcPageVo getOne(Long id) {
        if (id == null) return null;
        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        List<LcPageVo> list = dao.list(map);
        if (list.isEmpty()) return null;
        return list.get(0);
    }

    @Override
    public Object detail(Long id) {
        LcPageVo et = this.getOne(id);
        if (et == null) throw new BizException(SysConstant.No_Data);
        LcDetailRes res = new LcDetailRes();
        BeanUtils.copyProperties(et, res);
        //发货仓库
        res.setStorages(lcShippingStorageDao.getChannelStorage(id));
        //发货地址
        res.setAddress(lcShippingAddressDao.getShippingAddress(id));
        //绑定客户
        res.setCompany(lcCompanyDao.getChannelCompany(id));
        //下单限制
        res.setRules(lcChannelRuleService.getChannelRule(id));

        return res;
    }

    @Override
    public SingleResult pageInit() {
        Map<String, Object> result = new HashMap<>();
        result.put("carrier", this.getCarrierList());
        result.put("operateSign", this.getChannelOperateSign());
        result.put("calculateType", this.getChannelCalculateType());
        return SingleResult.success(result);
    }

    public List<Map<Object, Object>> getChannelOperateSign() {
        List<Map<Object, Object>> result = new ArrayList<>();
        for (StaticDict.Rule_Operate_Sign value : StaticDict.Rule_Operate_Sign.values()) {
            if (!value.getSource().contains("channel")) continue;
            Map<Object, Object> map = new HashMap<>();
            map.put("id", value.getValue());
            map.put("name", value.getText());
            result.add(map);
        }
        return result;
    }


    public List<Map<String, Object>> getChannelCalculateType() {
        List<Map<String, Object>> result = new ArrayList<>();
        for (StaticDict.Channel_Calculate_Type value : StaticDict.Channel_Calculate_Type.values()) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", value.getValue());
            map.put("name", value.getText());
            result.add(map);
        }
        return result;
    }

    public List<Map<String, String>> getCarrierList() {
        List<Map<String, String>> result = new ArrayList<>();
        for (StaticDict.Lc_Carrier value : StaticDict.Lc_Carrier.values()) {
            Map<String, String> map = new HashMap<>();
            map.put("id", value.getValue());
            map.put("name", value.getText());
            result.add(map);
        }
        return result;
    }

    @Override
    public List<LcChannelPageRes> getList(Map<String, Object> map) {
        List<LcPageVo> list = dao.list(map);
        return BeanCopierUtils.listCopyMapper(list, LcPageVo.class, LcChannelPageRes.class);
    }

    @Override
    public Map<Long, String> getChannelMap(Long tenantId) {
        List<LogisticsChannelDo> logisticsChannelDos = dao.selectList(new LambdaQueryWrapper<LogisticsChannelDo>().eq(LogisticsChannelDo::getTenantId, tenantId));
        return logisticsChannelDos.stream().collect(Collectors.toMap(LogisticsChannelDo::getId, LogisticsChannelDo::getChannelCode, (v1, v2) -> v1));
    }

    @Override
    public PageResult getListPage(Map<String, Object> map) {
        IPage<LcPageVo> page = pageInitDto(map);
        page = dao.list(page, map);
        List<LcChannelPageRes> resList = BeanCopierUtils.listCopyMapper(page.getRecords(), LcPageVo.class, LcChannelPageRes.class);
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    private IPage<LcPageVo> pageInitDto(Map<String, Object> map) {
        IPage<LcPageVo> page = new Page<>();
        page.setSize(map.get("pageSize") != null ? Long.parseLong(map.get("pageSize").toString()) : 10);
        page.setCurrent(map.get("current") != null ? Long.parseLong(map.get("current").toString()) : 1);
        return page;
    }

    @Override
    public void switchChannel(LaSwitchReq req, Long userId) {
        LogisticsChannelDo et = dao.selectById(req.getId());
        if (et == null) throw new BizException(SysConstant.No_Data);
        et.setEnable(req.getEnable());
        et.setUpdateBy(userId);
        dao.updateById(et);
    }


    @Override
    public void bindAddress(LcShippingAddressVoAddReq req, Long userId) {
        Long userTenantId = userService.getUserTenantId(userId);
        List<ChannelWarehouseVo> storages = warehouseService.getWarehouseListForChannel(req.getChannelId(), userTenantId);
        List<Long> collect = storages.stream().map(ChannelWarehouseVo::getStorageId).collect(Collectors.toList());
        if (!collect.contains(req.getStorageId())) throw new BizException(SysConstant.No_Data);
        LcShippingAddressDo et = new LcShippingAddressDo();
        BeanUtils.copyProperties(req, et);
        lcShippingAddressDao.insert(et);
    }

    @Override
    public void bindCompany(LcBindCompanyReq req, Long userId) {
        LogisticsChannelDo et = dao.selectById(req.getId());
        if (et == null) throw new BizException(SysConstant.No_Data);
        if (et.getCustomerCheckType() != req.getCustomerCheckType()) {
            et.setCustomerCheckType(req.getCustomerCheckType());
            et.setUpdateBy(userId);
            dao.updateById(et);
        }
        this.updateCompany(et.getId(), req.getCompany(), userId);
    }


    @Override
    public List<LcOptionRes> getLcForChoice(Long warehouseId, Long companyId, Long tenantId) {
        return this.getLcForOut("oms", warehouseId, companyId, tenantId);
    }

    //根据客户 仓库 获取支持的物流渠道
    @Override
    public List<LcOptionRes> getLcForOut(Long warehouseId, Long companyId, Long tenantId) {
        return this.getLcForOut("wms", warehouseId, companyId, tenantId);
    }


    @Override
    public List<LcOptionRes> getLcForOut(String source, Long warehouseId, Long companyId, Long tenantId) {
        List<LcOptionVo> lcOptions = dao.getLcOptions(warehouseId, companyId, tenantId);
        List<LcOptionRes> resList = BeanCopierUtils.listCopyMapper(lcOptions, LcOptionVo.class, LcOptionRes.class);
        for (LcOptionRes res : resList) {
            //下单限制
            res.setRules(lcChannelRuleService.getChannelRule(res.getId()));
        }
        //如果开启了 可以选择 价格最低的渠道
        OmpSystemEntity wmsSet = systemSetService.getOmpSet(tenantId);
        if (wmsSet != null && wmsSet.getOmp().getAutoChannel() == 1 && "oms".equals(source)) {
            LcOptionRes res = new LcOptionRes();
            res.setId(-1L);
            res.setChannelCode("auto");
            res.setChannelName("自动选取价格最低的物流渠道");
            res.setInsuranceFlag(1);
            res.setSignatureType("DIRECT,INDIRECT,ADULT");
            res.setSizeUnit(StaticDict.OMP_UnitMeasurement.Cm.getValue());
            resList.add(0, res);
        }
        return resList;

    }

    @Override
    public List<LcOptionRes> getLcList(Long warehouseId, Long companyId, Long tenantId) {
        List<LcOptionVo> lcOptions = dao.getLcOptions(warehouseId, companyId, tenantId);
        return BeanCopierUtils.listCopyMapper(lcOptions, LcOptionVo.class, LcOptionRes.class);
    }


}
